package org.ia.efactura;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.Signature;
import java.security.cert.X509Certificate;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.ssl.PKCS8Key;

 /**
  * Clase Encoder
  * @author oscar
  *
  */
public class Encoder { 

	
	public Encoder(){
	
	}
	
	/**
	 * Obtiene el sello digital aplicando una codificacion MD5WithRSA a la cadena original.
	 * @param cadena_original Cadena original.
	 * @param clave_privada Clave privada.
	 * @param cert_publico Ruta a la llave publica. (key file).
	 * @return Cadena con el sello digital.
	 */
	public String getSelloDigital(String cadena_original, String clave_privada, String cert_publico){
		String sello_digital = "";
			try {
				if(cadena_original == null || cadena_original.isEmpty()){
					throw new Exception("Error: El valor de la cadena orginal no puede ser nulo.");
				}else if(clave_privada == null || clave_privada.isEmpty()){
					throw new Exception("Error:  Por favor especifique la clave privada.");
				}else if(cert_publico == null || cert_publico.isEmpty()){
					throw new Exception("Error: Por favor especifique la ruta del certificado publico.");
				}
				sello_digital = this.EncodeMD5RSA(cadena_original, clave_privada, cert_publico);
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		return sello_digital;
	}
	
	/**
	 * Realiza el proceso de codificar la cadena original con el algoritmo MD5WithRSA.
	 * @param cadena_original Cadena original.
	 * @param clave_privada Clave privada.
	 * @param cert_publico Ruta donde se encuentra el certificado publico (key).
	 * @return Regresa la cadena codificada en MD5 y RSA.
	 */
	private String EncodeMD5RSA(String cadena_original, String clave_privada, String cert_publico){
		FileInputStream fin = null;		

		try
		{
		    fin = new FileInputStream (cert_publico);
			
		    PKCS8Key pkcs8 = new PKCS8Key(fin, clave_privada.toCharArray());
			
			//obtiene clave privada
			java.security.PrivateKey pk = pkcs8.getPrivateKey(); 

			//to md5 & rsa
			Signature firma = Signature.getInstance("MD5withRSA"); 
			firma.initSign(pk); 
			
			//pasamos firma original
			firma.update(cadena_original.getBytes("UTF-8")); 
			
			//cadena encriptada
			byte[] cadenaFirmada = firma.sign(); 

			//sello digital
			String selloDigital = new String(Base64.encodeBase64(cadenaFirmada)); 
	
			return selloDigital;

		}catch (FileNotFoundException e)
		{
			System.err.println ("Error: el archivo '" + cert_publico + "' no fue encontrado. ");
			e.printStackTrace();
		}
		catch(Exception e){
			System.err.println("Error: problema fue encontrado durante la codificacion.");
			e.printStackTrace();
		}
		finally {
			try {
				fin.close();
			}
			catch(Exception ex) {
			}
		}
		return null;
	}
	
	
	/** Regresa el certificado representado como una cadena de caracteres.
	 * @param cer_file Ruta al archivo del certificado (cer file).
	 * @return Regresa el certificado.
	 */
	public String getCertificado(String cer_file){
		String certDigital = null;
		X509Certificate cert = null;

		FileInputStream fis = null;
		ByteArrayInputStream bais = null;
		try {
			fis = new FileInputStream(cer_file);
			byte value[] = new byte[fis.available()];
			fis.read(value);
			bais = new ByteArrayInputStream(value);
			java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
			cert = (X509Certificate)cf.generateCertificate(bais);
			certDigital = new String(Base64.encodeBase64(cert.getEncoded())); 
			
		}catch (FileNotFoundException e)
		{
			System.err.println ("Error: el archivo '" + cer_file + "' no fue encontrado. ");
			e.printStackTrace();
		}
		catch(Exception e){
			System.err.println("Error: problema al leer el certificado publico.");
			e.printStackTrace();
		}
		finally {
			try {
				fis.close();
				bais.close();
			}
			catch(Exception ex) {
			}
		}
		return certDigital;
	}
	
} 